Replace AnyHashable#772
Merged
Merged
Conversation
90f5291 to
024060e
Compare
ccec5ab to
8c98396
Compare
There was a problem hiding this comment.
Pull request overview
This PR moves several public APIs away from AnyHashable toward Sendable-compatible identifiers and a new type-erased AnySendableHashable, supporting the broader Swift 6 strict concurrency effort.
Changes:
- Introduces
AnySendableHashableand applies it to decoration, HTTP request, and content attribute metadata. - Replaces pointer and input observer token identifiers with Sendable-specific types.
- Updates navigator/test app/docs call sites to unwrap type-erased config values.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
TestApp/Sources/Reader/Common/VisualReaderViewController.swift |
Updates page-list decoration config extraction to use unwrap(as:). |
Sources/Shared/Toolkit/HTTP/HTTPRequest.swift |
Makes HTTPRequest Sendable and updates userInfo typing. |
Sources/Shared/Toolkit/AnySendableHashable.swift |
Adds the new Sendable Hashable type-erasure wrapper. |
Sources/Shared/Publication/Services/Content/Content.swift |
Updates content attributes to store Sendable hashable values. |
Sources/Navigator/PDF/PDFNavigatorViewController.swift |
Wraps gesture object identifiers in PointerId. |
Sources/Navigator/Input/Pointer/PointerEvent.swift |
Makes pointer event types Sendable and introduces PointerId. |
Sources/Navigator/Input/Pointer/DragPointerObserver.swift |
Updates drag observer state to store PointerId. |
Sources/Navigator/Input/Pointer/ActivatePointerObserver.swift |
Updates activation observer state to store PointerId. |
Sources/Navigator/Input/InputObservingGestureRecognizerAdapter.swift |
Updates pending pointer tracking to key by PointerId. |
Sources/Navigator/Input/InputObservableViewController.swift |
Creates pointer IDs with the new PointerId enum. |
Sources/Navigator/Input/InputObservable.swift |
Changes input observable token IDs to UUID and marks tokens Sendable. |
Sources/Navigator/EPUB/HTMLDecorationTemplate.swift |
Updates highlight config extraction to use unwrap(as:). |
Sources/Navigator/EPUB/EPUBSpreadView.swift |
Converts JavaScript pointer IDs into PointerId.int. |
Sources/Navigator/Decorator/DecorableNavigator.swift |
Updates decoration metadata/config to use AnySendableHashable and marks decoration types Sendable. |
docs/Guides/Navigator/Decorations.md |
Updates decoration guide sample to use unwrap(as:). |
Comments suppressed due to low confidence (2)
Sources/Navigator/Decorator/DecorableNavigator.swift:134
- When callers already have an
AnySendableHashableand pass it asconfig, this generic initializer wraps it again, so laterstyle.config?.unwrap(as: OriginalConfig.self)returns nil because the stored base is the wrapper rather than the original value. Sinceconfigis exposed asAnySendableHashable?, this needs an overload or special handling to avoid nested wrappers.
public init<T: Hashable & Sendable>(id: Id, config: T? = nil) {
self.id = id
self.config = config.map(AnySendableHashable.init)
Sources/Shared/Toolkit/AnySendableHashable.swift:22
- The equality closure compares using only the left-hand side's stored type, which can make equality asymmetric for class hierarchies (for example a wrapped superclass value may consider a wrapped subclass value equal, while the reverse comparison fails).
Hashablerequires symmetric equality, so this can lead to incorrectSet/Dictionarybehavior forAnySendableHashablevalues.
public static func == (lhs: Self, rhs: Self) -> Bool {
lhs.equals(rhs.base)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
fce12f6 to
c7ff1de
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AnyHashable does not conform with Sendable. Replaced usages of it, including the introduction
AnySendableHashable: A new package private type-erased wrapper for values that conform to both Hashable and Sendable. It includes an.unwrap(as:)function for safe, generic extraction of the underlying value.Public API Breaking Changes
Pointer,TouchPointer,MousePointer: Theidproperty type was changed fromAnyHashabletoPointerId.InputObservableToken: Theidproperty type was changed fromAnyHashabletoUUID.Decoration: TheuserInfodictionary was changed from[AnyHashable: AnyHashable]to[String: AnyHashable].ContentAttributesHolder: The generic accessors (subscript<T>,attribute<T>,attributes<T>) were updated to restrict the generic parameterTtoHashable & Sendable.Related to #758.